package com.lry.rpc.netty.processor;

import com.lry.common.CommonConstants;
import com.lry.protocol.RpcInvocation;
import com.lry.protocol.RpcMessage;
import com.lry.protocol.RpcResult;
import com.lry.rpc.config.RpcServiceBean;
import com.lry.rpc.netty.BeanKey;
import com.lry.rpc.netty.MsgType;
import com.lry.rpc.netty.RpcContext;
import com.lry.rpc.netty.server.ServerCache;
import com.lry.spi.LoadLevel;
import com.lry.util.CollectionUtils;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

@Slf4j
@LoadLevel(name = "rpc_request")
public class RpcRequestProcessor implements Processor{


    @Override
    public void process(Channel channel, RpcMessage request) throws Exception{
        request.setMessageType(MsgType.RPC_RESPONSE.getCode());
        RpcInvocation rpcInvocation = (RpcInvocation) request.getBody();

        RpcServiceBean rpcServiceBean = ServerCache.getService(rpcInvocation);
        Object service = rpcServiceBean.getRef();
        request.setBody(null);

        for (Method method : service.getClass().getDeclaredMethods()) {
            if (method.getName().equals(rpcInvocation.getTargetMethod())&&
                    paramTypeEquals(method,rpcInvocation.getArgTypes())) {
                try {
                    method.setAccessible(true);
                    Object ret = method.invoke(service,rpcInvocation.getArgs());
                    RpcResult rpcResult = new RpcResult(ret,null);
                    request.setBody(rpcResult);
                    channel.writeAndFlush(request);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw e;
                }
                break;
            }
        }
    }

    private boolean paramTypeEquals(Method method,Class[] argTypes){
        Class<?>[] parameterTypes = method.getParameterTypes();
        if(parameterTypes.length!=argTypes.length){
            return false;
        }
        boolean ans = true;
        for(int i=0;i<parameterTypes.length;i++){
            if(!parameterTypes[i].equals(argTypes[i])){
                ans = false;
            }
        }
        return ans;
    }
}
